// Ruslan K, Syler C, Michael T, Eric P, Chan J
// mouse.cpp
// 25 September 2011
// Purpose: definitions for Mouse class       

#include "mouse.h"
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;

Mouse::Mouse(const Map & m):				// Default Constructor. Assigns mouse to starting position of map
coord(m.getStart()), _trail(new int[m.getH()]), _mouseRoute("")
{
	for(int ii=0; ii<m.getH(); ii++)		// sets values in _trail array = 0		
		_trail[ii]=0;
	_trail[coord._y]=coord._x;				// sets starting position as trail of mouse
}

bool Mouse::solve(const Map & m)			// solves map
{
	int height=m.getH();					// height of 2d array (size of 1d array)		
	unsigned int mask=coord._x;				// starting x positions of mouse
	int index=coord._y;						// starting y positions of mouse
	Coordinate finish=m.getFinish();		// finish position of the mouse	
	int * maze=new  int [height];			
	maze=m.getMap();						// copies map array
	vector<int> intersectionX;				// stores intersections (x positions) 
	vector<int> intersectionY;				// stores intersections (y positions)

	maze[index] = maze[index] | mask;	// assigns a one to the position that the mouse is at in the copied maze
										// that is so the mouse wouldn"t go back taking the same route
	while(index!=finish._y || mask!=finish._x)
	{
		// checks if there are openinigs to (left, right) if true sets intersection
		if(checkLeft(maze,index,mask) && checkRight(maze,index,mask))
		{
			intersectionX.push_back(mask);
			intersectionY.push_back(index);
		}
		// checks if there are openinigs to (left, down) if true sets intersection
		else if(checkLeft(maze,index,mask) && checkDown(maze,index,mask,height))
		{
			intersectionX.push_back(mask);
			intersectionY.push_back(index);
		}
		// checks if there are openinigs to (left, up) if true sets intersection
		else if(checkLeft(maze,index,mask) && checkUp(maze,index,mask))
		{
			intersectionX.push_back(mask);
			intersectionY.push_back(index);
		}
		// checks if there are openinigs to (right up) if true sets intersection
		else if(checkRight(maze,index,mask) && checkUp(maze,index,mask))
		{
			intersectionX.push_back(mask);
			intersectionY.push_back(index);
		}
		// checks if there are openinigs to (right, down) if true sets intersection
		else if(checkRight(maze,index,mask) && checkDown(maze,index,mask,height))
		{
			intersectionX.push_back(mask);
			intersectionY.push_back(index);
		}
		 //Makes sure 
		if(mask!=1<<31)
		{
			// if dead end, mouse teleports back to  most recent intersection
			if(checkLeft(maze,index,mask)==false && checkRight(maze,index,mask)==false &&
			   checkDown(maze,index,mask,height)==false && checkUp(maze,index,mask)==false)
			{
				index=intersectionY[intersectionY.size()-1];
				intersectionY.pop_back();
				mask=intersectionX[intersectionX.size()-1];	// mouse teleports back to intersection
				intersectionX.pop_back();
				_mouseRoute.push_back('i');
				cout<<"i";
				cout<<index;
			}
		}
		// Moves right if possible
		if(checkRight(maze,index,mask))
		{
			moveRight(maze,index,mask);
			maze[index] = maze[index] | mask;
			_mouseRoute.push_back('r');
			cout<<"r";
		}
		// Moves left if possible;
		else if(checkLeft(maze,index,mask))
		{
			moveLeft(maze,index,mask);	
			maze[index] = maze[index] | mask;	// assigns a one to the copied maze to where the mouse moved to
			_mouseRoute.push_back('l');
			cout<<"l";
		}
		// Moves down if possible
		else if(checkDown(maze,index,mask,height))
		{
			moveDown(maze,index,mask,height);
			maze[index] = maze[index] | mask;
			_mouseRoute.push_back('d');
			cout<<"d";
		}
		// Moves up if possible
		else if(checkUp(maze,index,mask))
		{
			moveUp(maze,index,mask);
			maze[index] = maze[index] | mask;
			_mouseRoute.push_back('u');
			cout<<"u";
		}
		if(mask==coord._x && index==coord._y)
		{
			cout<<endl<<"START"<<endl;
		}

	}
	delete [] maze;
	return true;	
}
	
void Mouse::displayMap(const Map & m)           // Prints _trail(steps mouset took to solve the puzzle
{
	cout<<endl<<endl<<"ROUTE MOUSE TOOK"<<endl<<endl;
	for(int y=0;y<m.getH();y++)
    {
            for(int x=31;x>=0;x--)
            {
                    int temp = _trail[y];
                    temp= temp >> x;
                    temp= temp&1;
                    if(temp==1)
                    {
						 cout<<1;
                    }
                    else
                    {
                         cout<<0;
                    }
            }
            cout<<endl;
    }
	cout<<endl;
}


bool Mouse::moveLeft(const int maze[], const int index,  unsigned int & mask)     // Moves left and returns if the action was successful
{
		mask=mask<<1;	// mouse moves left 				
		_trail[index] = _trail[index] | mask;	// saves the movement in _trail array
		return true;
}

bool Mouse::moveRight(const int maze[], const int index,  unsigned int & mask)   // Moves right and returns if the action was successful
{
		mask=mask>>1;	// mouse moves right
		_trail[index] = _trail[index] | mask;	// saves the movement in _trail array
		return true;
}

bool Mouse::moveUp(const int maze[], int & index, const  unsigned int mask)     // Moves up and returns if the action was successful
{
		--index;	// mouse moves up
		_trail[index] = _trail[index] | mask;	// saves the movement in _trail array
		return true;
}

												
bool Mouse::moveDown(const int maze[], int & index, const unsigned int  mask,  // Moves down and returns if the action was successful
					 const int height) 
{
		++index;	// mouse moves down 
		_trail[index] = _trail[index] | mask;	// saves the movement in _trail array
		return true;
}

bool Mouse::checkLeft(const int maze[], const int index, const unsigned int  mask)	// returns true if mouse can move left
{
	if(mask==(1<<31))				// If there is a left boundary (33rd bit) to the left of mouse, returns false   
		return false;
	else if(maze[index] & mask<<1)	// If there is a wall (or 1 on maze) to the left of the mouse, returns false
		return false;
	else
		return true;
}
bool Mouse::checkRight(const int maze[], const int index, const unsigned int  mask)	// returns true if mouse can move right
{
	if(mask==1)						// If there is a right boundary (-1 bit) to the right of mouse, returns false
		return false;
	else if(maze[index] & mask>>1)	// If there is a wall (or 1 on maze) to the right of the mouse, returns false
		return false;
	else
		return true;
}
bool Mouse::checkUp(const int maze[], const int index, const unsigned int  mask)	// returns true if mouse can move up
{
	if((index-1)<0)					// If there is boundary above the mouse, returns false
		return false;
	else if(maze[index-1] & mask)	// If there is a wall (or 1 on maze) above mouse, returns false
		return false;
	else
		return true;
}
bool Mouse::checkDown(const int maze[], const int index, const unsigned int mask, const int height)	// returns true if mouse can move down
{
	if((index+1)>height)			// If there is boundary below the mouse, returns false
		return false;
	else if(maze[index+1] & mask)	// If there is a wall (or 1 on maze) below mouse, returns false
		return false;
	else
		return true;
}
void Mouse::displayMouseRoute()
{
	cout<<"ROUTE MOUSE TOOK AS A STRING"<<endl<<endl;
	cout<<_mouseRoute<<endl<<endl;
}